﻿using Org.BouncyCastle.Asn1.X509;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Generators;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Math;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.X509;
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography.X509Certificates;
using System.Text;

namespace CreateSign
{
    class Class1
    {
//产生证书文件
    internal class CertificateGenerate
    {
        /// <summary>
        /// 公钥类型
        /// </summary>
        private PublicKeyKind publicKeyKind = PublicKeyKind.UNKNOWN;
        private AsymmetricCipherKeyPair createdkeyPair = null; 
        
        /// <summary>
        /// 创建公密钥对
        /// </summary>
        /// <returns></returns>
        protected virtual AsymmetricCipherKeyPair createRasKeyPair()
        {
            //RSA密钥对的构造器
            RsaKeyPairGenerator keyGenerator = new RsaKeyPairGenerator();
            //RSA密钥构造器的参数
            RsaKeyGenerationParameters param = new RsaKeyGenerationParameters(BigInteger.ValueOf(3), new SecureRandom(), 1024, 25);
            //用参数初始化密钥构造器
            keyGenerator.Init(param);
            //产生密钥对
            AsymmetricCipherKeyPair keyPair = keyGenerator.GenerateKeyPair();
            return keyPair;
        }
 
        /// <summary>
        /// 创建证书实体
        /// </summary>
        /// <returns></returns>
        private Org.BouncyCastle.X509.X509Certificate createX509Certificate(AsymmetricKeyParameter publicKey, AsymmetricKeyParameter privateKey)
        {
            IDictionary attrs = new Hashtable();
            attrs[X509Name.E] = "";
            attrs[X509Name.CN] = "";
            attrs[X509Name.O] = "";
            attrs[X509Name.C] = "";
            attrs[X509Name.L] = "";
            attrs[X509Name.T] = "";
 
            IList ord = new ArrayList();
            ord.Add(X509Name.E);
            ord.Add(X509Name.CN);
            ord.Add(X509Name.O);
            ord.Add(X509Name.C);
            ord.Add(X509Name.L);
            ord.Add(X509Name.T);
 
            X509V3CertificateGenerator certGen = new X509V3CertificateGenerator();
            certGen.SetSerialNumber(BigInteger.One);
            certGen.SetIssuerDN(new X509Name(ord, attrs));

            certGen.SetNotBefore(DateTime.Today.Subtract(new TimeSpan(1, 0, 0, 0)));
            certGen.SetNotAfter(DateTime.Today.AddYears(150));

            certGen.SetSubjectDN(new X509Name(ord, attrs));
            certGen.SetPublicKey(publicKey);

            certGen.AddExtension(X509Extensions.BasicConstraints, true, new BasicConstraints(false));
            certGen.AddExtension(X509Extensions.AuthorityKeyIdentifier, true, new AuthorityKeyIdentifier(SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(publicKey)));
            Org.BouncyCastle.X509.X509Certificate x509 = certGen.Generate(new Asn1SignatureFactory("SHA1withRSA", privateKey, new SecureRandom()));
 
            x509.CheckValidity();
            x509.Verify(publicKey);
            return x509;
        }
                
        internal void CreateIfNotExist()
        {
            X509Store store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
            store.Open(OpenFlags.ReadWrite);
            bool isExist = false;
            //轮询存储区中的所有证书
            foreach (X509Certificate2 myX509Certificate2 in store.Certificates)
            {
                if (myX509Certificate2.FriendlyName.Equals("" + publicKeyKind.ToString()))
                {
                    isExist = true;
                    break;
                }
            }
            if (!isExist)
            {
                //产生密钥对
                if (createdkeyPair == null)
                    createdkeyPair = createRasKeyPair();
                //获取公钥和密钥
                AsymmetricKeyParameter publicKey = createdkeyPair.Public;
                AsymmetricKeyParameter privateKey = createdkeyPair.Private;
                if (((RsaKeyParameters)publicKey).Modulus.BitLength < 1024)
                    throw new Exception("failed key generation (1024) length test");
                Org.BouncyCastle.X509.X509Certificate x509 = createX509Certificate(publicKey, privateKey);
                X509Certificate2 myPrivateCertificate = new X509Certificate2(x509.GetEncoded(), PublicKeyFactory.cerificatePassword, X509KeyStorageFlags.Exportable);
                myPrivateCertificate.FriendlyName = "" + publicKeyKind.ToString(); 
                myPrivateCertificate.PrivateKey = DotNetUtilities.ToRSA(privateKey as RsaPrivateCrtKeyParameters);
                store.Add(myPrivateCertificate);
            }
            store.Close(); 
        }
 
        //导出
        internal void Export(string path)
        {
            X509Store store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
            store.Open(OpenFlags.ReadOnly);
            //轮询存储区中的所有证书
            X509Certificate2 currrent = null;
            foreach (X509Certificate2 myX509Certificate2 in store.Certificates)
            {
                if (myX509Certificate2.FriendlyName.Equals("" + publicKeyKind.ToString()))
                {
                    currrent = myX509Certificate2;
                    break;
                }
            }
            if (currrent == null)
                throw new Exception("未找到相关证书文件.");
            byte[] cerByte = currrent.Export(X509ContentType.Cert);
            using (FileStream fileStream = new FileStream(path, FileMode.Create))
            {
                // Write the data to the file, byte by byte.     
                for (int i = 0; i < cerByte.Length; i++)
                    fileStream.WriteByte(cerByte[i]);
                // Set the stream position to the beginning of the file.     
                fileStream.Seek(0, SeekOrigin.Begin);
                // Read and verify the data.     
                for (int i = 0; i < fileStream.Length; i++)
                {
                    if (cerByte[i] != fileStream.ReadByte())
                    {
                        fileStream.Close();
                    }
                }
                fileStream.Close();
            }
            currrent = null;
        }
 
        internal PublicKeyKind PublicKeyKind
        {
            get
            {
                return this.publicKeyKind;
            }
            set
            {
                if (value != publicKeyKind)
                    this.publicKeyKind = value;
            }
        }
    }
    }
}

